package ua.pp.bizon.cripto.keystore;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.*;
import javax.crypto.spec.*;

public class AES128 implements ICrypter {

    private AES128(){
        
    }
    public static ICrypter get(){
        return new AES128();
    }
    /**
     * Turns array of bytes into string
     * 
     * @param buf
     *            Array of bytes to convert to hex string
     * @return Generated hex string
     */
    public static String asHex(byte buf[]) {
        StringBuffer strbuf = new StringBuffer(buf.length * 2);
        int i;

        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10)
                strbuf.append("0");

            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }

        return strbuf.toString();
    }
    
    public static byte[] asString(String s) {
        byte[] buf = new byte[s.length() / 2];
        int i;

        for (i = 0; i < buf.length; i++) {
            buf[i] = (byte) (asString(s.charAt(i*2))*16 + asString(s.charAt((i*2 )+1)) );
        }

        return buf;
    }
    
    private static byte asString(char a){
        return a >= 'a' ? ((byte) (a - 'a' + 10)) : ((byte) (a - '0')) ;
    }

  
    
    /* (non-Javadoc)
     * @see ua.pp.bizon.cripto.keystore.ICripter#crypt(java.lang.String)
     */
    @Override
    public byte[] crypt(String message) {
        return crypt(message.getBytes());
    }
    /* (non-Javadoc)
     * @see ua.pp.bizon.cripto.keystore.ICripter#crypt(byte[])
     */
    @Override
    public byte[] crypt(byte[] message) {
        SecretKeySpec skeySpec = new SecretKeySpec(getSert128(), "AES");

        try {
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] encrypted = cipher.doFinal(message);
            return encrypted;
        } catch (Exception e) {
            throw new RuntimeException("AES.crypt:" + e.getMessage(), e);
        } 

    }

    /* (non-Javadoc)
     * @see ua.pp.bizon.cripto.keystore.ICripter#decrypt(byte[])
     */
    @Override
    public byte[] decrypt(byte[] message) {
        SecretKeySpec skeySpec = new SecretKeySpec(getSert128(), "AES");

        try {
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] encrypted = cipher.doFinal(message);
            return encrypted;
        } catch (Exception e) {
            throw new RuntimeException("AES.decrypt:" + e.getMessage(), e);
        }
    }

    private static byte[] sert128;

    static byte[] getSert128() {
        if (sert128 == null)
            loadSertificate();
        return sert128;
    }

    static void loadSertificate() {
        File sertificate = new File("sert.key");
        try {
            if (sertificate.exists()) {
                FileInputStream fileInputStream = new FileInputStream(sertificate);
                sert128 = new byte[(int) sertificate.length()];
                fileInputStream.read(sert128);
                fileInputStream.close();
            } else {
                KeyGenerator kgen;
                kgen = KeyGenerator.getInstance("AES");
                kgen.init(128);
                SecretKey skey = kgen.generateKey();
                sert128 = skey.getEncoded();
                FileOutputStream fileOutputStream = new FileOutputStream(sertificate);
                fileOutputStream.write(sert128);
                fileOutputStream.close();
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("AES.loadSertificate:" + e.getMessage(), e);
        } catch (IOException e) {
            throw new RuntimeException("AES.loadSertificate:" + e.getMessage(), e);
        }
    }
}